package at.jku.isse.ecco.web.rest.resource;

import at.jku.isse.ecco.SerializeUtil;
import at.jku.isse.ecco.adapter.dispatch.DirectoryArtifactData;
import at.jku.isse.ecco.adapter.dispatch.PluginArtifactData;
import at.jku.isse.ecco.adapter.java.data.ClassArtifactData;
import at.jku.isse.ecco.adapter.java.data.DocArtifactData;
import at.jku.isse.ecco.adapter.java.data.FieldArtifactData;
import at.jku.isse.ecco.adapter.java.data.MethodArtifactData;
import at.jku.isse.ecco.composition.LazyCompositionNode;
import at.jku.isse.ecco.composition.LazyCompositionRootNode;
import at.jku.isse.ecco.core.Association;
import at.jku.isse.ecco.service.EccoService;
import at.jku.isse.ecco.storage.mem.core.MemAssociation;
import at.jku.isse.ecco.tree.Node;
import at.jku.isse.ecco.tree.RootNode;
import at.jku.isse.ecco.web.rest.EccoApplication;
import at.jku.isse.ecco.web.rest.EccoResource;
import at.jku.isse.ecco.web.rest.dto.AssociationDTO;
import at.jku.isse.ecco.web.rest.dto.MethodDTO;
import at.jku.isse.ecco.web.rest.dto.NodeDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.glassfish.grizzly.http.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.io.*;
import java.nio.file.Paths;
import java.util.*;

@Path("/artifacts")
public class ArtifactsResource extends EccoResource {

    private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesResource.class);

    @Context
    private Application application;

    @Context
    private Configuration configuration;


    private EccoService getService() {
        if (!(this.application instanceof EccoApplication))
            throw new RuntimeException("No or wrong application object injected.");

        EccoService eccoService = ((EccoApplication) this.application).getEccoService();

        return eccoService;
    }

    @GET
    @Path("/commit/{dir}")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public String Commit(@PathParam("dir")String dir){
        EccoService service=getService();
        java.nio.file.Path baseDir= Paths.get("D:\\study\\workspace1\\ecco-master\\examples\\lucene-src1\\"+dir);
        String configurationString ="";
        service.setBaseDir(baseDir);
        if (!configurationString.isEmpty())
            service.commit(configurationString);
        else
            service.commit();
        return "hello";
    }

    @GET
    @Path("/getAssociation")
    @Produces(MediaType.APPLICATION_JSON)
    public JSONObject getAssociation(){
//        response.setHeader("Access-Control-Allow-Origin", "*");
//        response.setHeader( "Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
//        response.setHeader( "Access-Control-Max-Age", "3600");
//        response.setHeader( "Access-Control-Allow-Headers", "x-requested-with,Authorization");
//        response.setHeader( "Access-Control-Allow-Credentials", "true");
        EccoService service=getService();
        Collection<? extends Association> associations=service.getRepository().getAssociations();

        List associationDTOCollections=new ArrayList<AssociationDTO>();
        Iterator<? extends Association> itr = associations.iterator();
        while (itr.hasNext()){
            AssociationDTO associationDTO=new AssociationDTO();
            Association association=itr.next();
            associationDTO.setId(association.getId());
            associationDTO.setCondition(association.computeCondition().getSimpleModuleRevisionConditionString());
            associationDTO.setNumArtifacts(association.getRootNode().countArtifacts());
            associationDTOCollections.add(associationDTO);
        }
        HashMap map=new HashMap();
        map.put("data", associationDTOCollections);
        JSONObject jsonObject=null;

        return new JSONObject(map);
    }
    @GET
    @Path("/getContainAssociation")
    @Produces(MediaType.APPLICATION_JSON)
    public JSONObject getContainAssociation(){
        EccoService service=getService();
        Collection<? extends Association> associations=service.getRepository().getAssociations();

        List<String> list = new ArrayList<>();
        Iterator<? extends Association> itr = associations.iterator();
        while (itr.hasNext()){
            Association association=itr.next();
            Node rootnode=association.getRootNode().getChildren().get(0);
            String condition= association.computeCondition().getSimpleModuleRevisionConditionString();
            getNode(list,rootnode,condition);
         }
        HashMap map=new HashMap();
        map.put("data", list);
        JSONObject jsonObject=null;

        return new JSONObject(map);
    }
    private List getNode(List list,Node rootnode,String condition){
        Jedis jedis=new Jedis("localhost",6379);
        String query=jedis.get("querystr");
        jedis.close();
        loopquery(condition,rootnode,query,list);
        return list;
    }
    private void loopquery(String conidtion,Node node,String query,List list){
        if(node.getNodeString().contains(query)){
            StringBuffer addstr=new StringBuffer();
            addstr.append(conidtion);
            Node temp=node;
            while (temp.getParent()!=null){
                if(ClassArtifactData.class.isInstance(temp.getParent().getArtifact().getData())){
                    addstr.append("-----------"+temp.getParent().getNodeString()+"--------"+node.getNodeString());
                    break;
                }
                temp=temp.getParent();
            }
            list.add(addstr.toString());
        }
        for(Node child:node.getChildren()){
            loopquery(conidtion,child, query, list);
        }
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/compose")
    @Produces(MediaType.APPLICATION_JSON)
    public JSONObject compose(String[] ids){
        EccoService service=getService();
        Collection<? extends Association> associations=service.getRepository().getAssociations();
        Node rootnode;
        NodeDTO nodeDTO=null;
        HashMap map=new HashMap();
        for(String id:ids){
            for(Association association:associations){
                if(association.getId().equals(id)){
                    map.put("association", association.computeCondition().getSimpleModuleConditionString());
                    rootnode=association.getRootNode().getChildren().get(0);
                    nodeDTO=new NodeDTO();
                    nodeDTO.setName("..");
                    setNode(nodeDTO, rootnode,association.computeCondition().getSimpleModuleConditionString());
                    show(rootnode);
                }
            }
        }



        map.put("data", nodeDTO);
        return new JSONObject(map);
    }

    private void show(Node rootnode) {
        ArrayList<String> fieldlist=new ArrayList();
        ArrayList<String> methodlist=new ArrayList();
        ArrayList<Node>   nodes=new ArrayList<>();
        findAllNOde(rootnode,nodes);
        findfield(rootnode, fieldlist);
        findMethod(rootnode, methodlist);
        for(String key:fieldlist){
            ArrayList<Node> containNodes=new ArrayList<>();
            System.out.println("-------------------------");
            for(Node node:nodes){
                findContain(key,node,containNodes);
            }
        }
        for(String key:methodlist){
            ArrayList<Node> containNodes=new ArrayList<>();
            System.out.println("-------------------------");
            for(Node node:nodes){
                findContain(key,node,containNodes);
            }
        }

    }

    private boolean findContain(String key, Node node, ArrayList<Node> containNodes) {
        int count=0;
        for(Node child:node.getChildren()){
            if(child.getNodeString().contains(key)){
                if(count==0){
                    System.out.println("关键词："+key);
                    count++;
                }
                printnode(child);
                return true;
            }else {
                boolean find=findContain(key, child,containNodes);
                if(find){
                    return true;
                }
            }
        }
        return false;
    }

    private void printnode(Node child) {
        while (!ClassArtifactData.class.isInstance(child.getArtifact().getData())){
            child=child.getParent();
        }
        System.out.println("*********");
        System.out.println("file:"+child.getNodeString());
        StringBuffer javafile=new StringBuffer();
        StringBuffer importfile=new StringBuffer();
        StringBuffer docfile=new StringBuffer();
        deeploop(child, javafile, importfile,docfile);
        System.out.println(importfile.toString()+docfile.toString()+javafile.toString());
        System.out.println("*********");
    }

    private void findAllNOde(Node rootnode, ArrayList<Node> nodes) {
        for(Node child:rootnode.getChildren()){
            if(ClassArtifactData.class.isInstance(child.getArtifact().getData())){
                nodes.add(child);
            }else {
                findAllNOde(child, nodes);
            }
        }
    }

    private void findfield(Node node,ArrayList fieldlist){
        for(Node child:node.getChildren()){
            if(FieldArtifactData.class.isInstance(child.getArtifact().getData())){
                String fieldstat=child.getNodeString();
                if(fieldstat.contains("=")){
                    fieldstat=fieldstat.substring(0, fieldstat.indexOf("="));
                }
                String[] fields=fieldstat.split(" ");
                String fied=fields[fields.length-1].trim();
                if(fied.length()>4){
                    fieldlist.add(fied);
                }

            }else if(DirectoryArtifactData.class.isInstance(child.getArtifact().getData())
                        ||PluginArtifactData.class.isInstance(child.getArtifact().getData())
                        ||ClassArtifactData.class.isInstance(child.getArtifact().getData())){
                findfield(child, fieldlist);
            }
        }

    }
    private void findMethod(Node node,ArrayList methodlist){
        for(Node child:node.getChildren()){
            if(MethodArtifactData.class.isInstance(child.getArtifact().getData())){
                String methodstat=child.getNodeString();
                if(methodstat.contains("(")){
                    methodstat=methodstat.substring(0, methodstat.indexOf("("));
                }
                String[] methods=methodstat.split(" ");
                String metho=methods[methods.length-1].trim();
                if(metho.length()>4){
                    methodlist.add(metho);
                }

            }else if(DirectoryArtifactData.class.isInstance(child.getArtifact().getData())
                    ||PluginArtifactData.class.isInstance(child.getArtifact().getData())
                    ||ClassArtifactData.class.isInstance(child.getArtifact().getData())){
                findMethod(child, methodlist);
            }
        }

    }


    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/getMethodList")
    @Produces(MediaType.APPLICATION_JSON)
    public JSONObject getMethodList(String[] ids){
        EccoService service=getService();
        Collection<? extends Association> associations=service.getRepository().getAssociations();
        Node rootnode;
        List<MethodDTO> methodDTOList=new ArrayList<>();
        HashMap map=new HashMap();
        for(String id:ids){
            for(Association association:associations){
                if(association.getId().equals(id)){
                    map.put("association", association.computeCondition().getSimpleModuleConditionString());
                    rootnode=association.getRootNode().getChildren().get(0);
                    setMethodNode(methodDTOList,rootnode);
                }
            }
        }



        map.put("data", methodDTOList);
        return new JSONObject(map);
    }




    private void setMethodNode(List<MethodDTO> list,Node node) {
        for(Node child:node.getChildren()){
            if(MethodArtifactData.class.isInstance(child.getArtifact().getData())){
                MethodDTO methodDTO=new MethodDTO();
                methodDTO.setType(0);
                methodDTO.setMethodname(child.getNodeString());
                methodDTO.setClassname(child.getParent().getNodeString());
                list.add(methodDTO);
            }else if(FieldArtifactData.class.isInstance(child.getArtifact().getData())){
                MethodDTO methodDTO=new MethodDTO();
                methodDTO.setType(1);
                methodDTO.setMethodname(child.getNodeString());
                methodDTO.setClassname(child.getParent().getNodeString());
                list.add(methodDTO);
            }else{
                setMethodNode(list, child);
            }
        }
    }


    public void setNode(NodeDTO nodeDTO,Node node,String condition){
        for(Node child:node.getChildren()){
            if(DirectoryArtifactData.class.isInstance(child.getArtifact().getData())){
                NodeDTO childNodeDto=new NodeDTO();
                childNodeDto.setName(child.getNodeString());
                nodeDTO.getChilds().add(childNodeDto);
//                list.add(child.getNodeString());
                setNode(childNodeDto,child,condition);
//                list.removeLast();
            }else if(PluginArtifactData.class.isInstance(child.getArtifact().getData())){
                NodeDTO childNodeDto=new NodeDTO();
                Node javaNode=child.getChildren().get(0);
                childNodeDto.setName(javaNode.getNodeString());
                String UUID=splitToLine(javaNode);//切分成一行
                //节点入redis
                Jedis jedis=new Jedis("localhost",6379);
                String javaFileId=composeJavaFile(jedis,javaNode,condition);
                jedis.close();
                childNodeDto.setUuid(UUID);
                childNodeDto.setJavaFileId(javaFileId);
                childNodeDto.setDir(child.getNodeString().substring(0,child.getNodeString().indexOf(" [")));
                nodeDTO.getChilds().add(childNodeDto);
            }
        }
    }

    private String composeJavaFile(Jedis jedis,Node javaNode,String condition) {
        StringBuffer javafile=new StringBuffer();
        StringBuffer importfile=new StringBuffer();
        String javaFileId=UUID.randomUUID().toString();
        deeploop(javaNode,javafile,importfile,new StringBuffer());
        String filename="D:\\study\\IRTool\\IRTool\\data\\lucene\\"+condition+"\\"+javaNode.getNodeString()+".txt";
        File file=new File("D:\\study\\IRTool\\IRTool\\data\\lucene\\"+condition);
        if(!file.exists()){
            file.mkdir();
        }
        try {
            FileWriter writer=new FileWriter(filename);
            writer.write(importfile.append(javafile).toString());
            writer.close();
            System.out.println("write:"+importfile.append(javafile).toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        jedis.set(javaFileId, importfile.append(javafile).toString());
        return javaFileId;
    }

    private void deeploop(Node javaNode, StringBuffer javafile,StringBuffer importfile,StringBuffer docfile) {
        if(ClassArtifactData.class.isInstance(javaNode.getArtifact().getData())){
            javafile.append(javaNode.getNodeString()+"{\n");
            for(Node child:javaNode.getChildren()){
                deeploop(child, javafile,importfile,docfile);
            }
            javafile.append("}\n");
        }else if(MethodArtifactData.class.isInstance(javaNode.getArtifact().getData())){
            javafile.append(javaNode.getNodeString()+"{\n");
            for(Node child:javaNode.getChildren()){
                deeploop(child, javafile,importfile,docfile);
            }
            javafile.append("}\n");
        }else if(DocArtifactData.class.isInstance(javaNode.getArtifact().getData())){
            docfile.append(javaNode.getNodeString()+"\n");
        }else {
            if (javaNode.getNodeString().startsWith("import")){
                importfile.append(javaNode.getNodeString()+"\n");
            }else {
                javafile.append(javaNode.getNodeString()+"\n");
            }
        }
    }
//    public String createDir(LinkedList<String> list){
//        StringBuffer stringBuffer=new StringBuffer();
//        for(String str:list){
//            stringBuffer.append(str+"\\");
//        }
//        return stringBuffer.toString();
//    }


    public String splitToLine(Node javaNode){
        UUID uuid=UUID.randomUUID();
//        FileInputStream inputStream = null;
//        try {
//            inputStream = new FileInputStream(dir);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Jedis jedis=new Jedis("localhost",6379);
        loop(jedis,uuid.toString(), javaNode);

        jedis.close();
        return uuid.toString();
    }

    public void loop(Jedis jedis,String uuid,Node javaNode){
        for(Node node:javaNode.getChildren()){
            jedis.lpush(uuid, node.toString());
            if(node.getChildren().size()>0){
                loop(jedis,uuid,node);
            }
        }
    }




//    @POST
//    @Consumes(MediaType.APPLICATION_JSON)
//    @Path("/compose1")
//    @Produces(MediaType.APPLICATION_JSON)
//    public JSONObject compose1(String[] ids){
//        EccoService service=getService();
//        Jedis jedis=new Jedis("localhost",6379);
//        LazyCompositionRootNode root=new LazyCompositionRootNode();
//        for(String id:ids){
//            if(jedis.get(id)!=null&&!"".equals(jedis.get(id))){
//                MemAssociation association= (MemAssociation) SerializeUtil.deserialize(jedis.get(id.getBytes()));
//                root.addOrigNode(association.getRootNode());
//            }
//        }
//        LazyCompositionRootNode root1=new LazyCompositionRootNode();
//        MemAssociation association1= (MemAssociation) SerializeUtil.deserialize(jedis.get(ids[0].getBytes()));
//        root1.addOrigNode(association1.getRootNode());
//
//        NodeDTO nodeDTO=new NodeDTO();
//        getJava((LazyCompositionNode)root1.getChildren().get(0),(LazyCompositionNode)root.getChildren().get(0),nodeDTO);
//        setDtoToRedis(nodeDTO);
//
//
//
//        NodeDTO rootnode=new NodeDTO();
//        rootnode=setNode(rootnode,(LazyCompositionNode)root.getChildren().get(0));
//        HashMap map=new HashMap();
//        map.put("data", rootnode);
//        return new JSONObject(map);
//    }

    public void setDtoToRedis(NodeDTO dto){
        Jedis jedis=null;
        for(NodeDTO nodeDTO:dto.getChilds()){
            if(nodeDTO.getName().startsWith(".")){
                if(jedis==null){
                    jedis=new Jedis("localhost",6379);
                }
                String[] rs=getJava1(nodeDTO);
                jedis.set(nodeDTO.getName(), rs[0]);
                jedis.set(nodeDTO.getName()+":line", rs[1]);
            }else {
                if(nodeDTO.getChilds().size()>0){
                    setDtoToRedis(nodeDTO);
                }
            }
        }
    }

    public String[] getJava1(NodeDTO dto){
        StringBuffer stringBuffer = new StringBuffer();
        List list=new ArrayList<Integer>();
        deepArray(dto,stringBuffer,list,1);
        String[] res={stringBuffer.toString(),list.toArray().toString()};
        return res;
    }
    public void deepArray(NodeDTO dto, StringBuffer str, List<Integer> nums, int line){
        for(NodeDTO nodeDTO:dto.getChilds()){
            if(nodeDTO.getChilds().size()>0){
                str.append("{"+nodeDTO.getName()+"\n");
                if(nodeDTO.isIn()){
                    nums.add(line);
                }
                line++;
                deepArray(nodeDTO, str, nums, line);
                str.append("}\n");
                line++;
            }else {
                str.append(nodeDTO.getName()+"\n");
                if(nodeDTO.isIn()){
                    nums.add(line);
                }
                line++;
            }
        }
    }

    public NodeDTO setNode(NodeDTO nodeDTO, LazyCompositionNode root){
        nodeDTO.setName(root.toString());
        for(Node node:root.getChildren()){
            NodeDTO nodeDTO1=new NodeDTO();
            nodeDTO.getChilds().add(nodeDTO1);
            setNode(nodeDTO1,(LazyCompositionNode)node);
        }
        return nodeDTO;
    }


    public void getJava(LazyCompositionNode node,LazyCompositionNode rootnode,NodeDTO nodeDTO){
        boolean in=false;
        for(Node node1:node.getChildren()){
            for(Node node2:rootnode.getChildren()){
                if(node1.toString().equals(node2.toString())){
                    ((LazyCompositionNode)node2).setIn(true);
                    in=true;
                    NodeDTO nNodeDTo=new NodeDTO(node2.toString(),true);
                    getJava((LazyCompositionNode)node1,(LazyCompositionNode)node2,nNodeDTo);
                    nodeDTO.getChilds().add(nNodeDTo);
                    break;
                }
            }
            if(!in){
                nodeDTO.getChilds().add(new NodeDTO(node1.toString(),true));
            }

        }
        for(Node node2:rootnode.getChildren()){
            if(((LazyCompositionNode)node2).isIn){
//                nodeDTO.getChilds().add(new NodeDTO(node2.toString(),true));
            }else {
                nodeDTO.getChilds().add(new NodeDTO(node2.toString(),false));
            }
        }
    }


//    @POST
//    @Consumes(MediaType.APPLICATION_JSON)
//    @Path("/migrationdetail")
//    @Produces(MediaType.APPLICATION_JSON)
//    public JSONObject migrationdetail(String[] ids){
//        EccoService service=getService();
//        Collection<? extends Association> associations=service.getRepository().getAssociations();
//        Node rootnode1;
//        Node rootnode2;
//        NodeDTO nodeDTO=null;
//        for(Association association:associations){
//            if(association.getId().equals(ids[0])){
//                rootnode1=association.getRootNode().getChildren().get(0);
////                    nodeDTO=new NodeDTO();
////                    nodeDTO.setName("..");
////                    setNode(nodeDTO, rootnode);
//            }
//            if(association.getId().equals(ids[1])){
//                rootnode2=association.getRootNode().getChildren().get(0);
//            }
//        }
//
//
//        HashMap map=new HashMap();
//        map.put("data", nodeDTO);
//        return new JSONObject(map);
//    }

//    public NodeDTO compare(Node node1,Node node2){
//
//    }

}
